#include "pch.h"
#include "XamlSurfaceRenderer.h"

using namespace std;
using namespace Dx;
using namespace Platform;
using namespace Microsoft::WRL;

inline void ThrowIfFailed(HRESULT hr)
{
    if (FAILED(hr))
    {
        throw Platform::Exception::CreateException(hr);
    }
}

XamlSurfaceRenderer::XamlSurfaceRenderer(GraphicsDeviceContextPtr const& gfx, Dx::SizeU const pixelSize, bool isOpaque) :
                                         SurfaceImageSource(pixelSize.Width, pixelSize.Height, isOpaque),
                                             m_gfx(gfx),
                                             m_pixelSize(pixelSize)
{
    CreateDeviceIndependentResources();
    CreateDeviceResources();
}

XamlSurfaceRenderer::~XamlSurfaceRenderer()
{

}

void XamlSurfaceRenderer::CreateDeviceIndependentResources()
{
    HRESULT hr = reinterpret_cast<IUnknown*>(this)->QueryInterface(IID_PPV_ARGS(&m_sisNative));
   
    ThrowIfFailed(hr);

    m_sisNative->Release();
}

void XamlSurfaceRenderer::CreateDeviceResources()
{
    auto dxgiDevice = m_gfx->GetD3DDevice().AsDxgi();

    HRESULT hr = m_sisNative->SetDevice(m_gfx->GetD2DDevice().Get());

    ThrowIfFailed(hr);
}

void XamlSurfaceRenderer::BeginDraw(Dxgi::Surface& surface, Dx::Point2F& offset) const
{
    RECT updateRectNative   = { 0 };
    updateRectNative.right  = m_pixelSize.Width;
    updateRectNative.bottom = m_pixelSize.Height;
    
    surface = nullptr;
    
    POINT drawOffset;
    
    HRESULT hr = m_sisNative->BeginDraw(updateRectNative, 
                                        __uuidof(IDXGISurface), 
                                        reinterpret_cast<void**>(surface.GetAddressOf()),
                                        &drawOffset);
    
    ThrowIfFailed(hr);
    
    offset.X = static_cast<float>(drawOffset.x);
    offset.Y = static_cast<float>(drawOffset.y);
}

void XamlSurfaceRenderer::EndDraw() const
{
    HRESULT hr = m_sisNative->EndDraw();

    ThrowIfFailed(hr);
}

auto XamlSurfaceRenderer::GetSize() const -> Dx::SizeU
{
    return m_pixelSize;
}

